<script lang="ts" setup>
import {
  getPermissionTree,
  getRolePermissionList,
  updateRolePermission
} from "@/api/modules/system";
import type {
  PermissionTree,
  PermissionVO,
  RolePermissionAssignParams
} from "@/api/modules/system/types";
import { ElMessage, ElTree } from "element-plus";
import { PlusColumn, PlusDrawerForm } from "plus-pro-components";
import { computed, nextTick, onMounted, ref, watch } from "vue";

defineOptions({
  name: "role-permission-assign"
});

const props = defineProps({
  visible: {
    type: Boolean,
    default: false
  },
  roleInfo: {
    type: Object,
    required: true
  }
});

const emit = defineEmits(["close", "success"]);

const visible = ref(props.visible);
const loading = ref(false);
const permissionTree = ref<PermissionTree[]>([]);
const selectedPermissionIds = ref<string[]>([]);
const originalPermissionIds = ref<string[]>([]);
const treeRef = ref<InstanceType<typeof ElTree>>();

// 计算属性：选中权限数量
const selectedCount = computed(() => selectedPermissionIds.value.length);

// 监听visible变化，当抽屉打开时加载数据
watch(
  () => props.visible,
  newVal => {
    visible.value = newVal;
    if (newVal && props.roleInfo?.id) {
      loadData();
      nextTick(() => {
        updateTreeSelection();
      });
    }
  }
);

// 监听roleInfo变化，当角色信息变化时重新加载数据
watch(
  () => props.roleInfo,
  newVal => {
    if (visible.value && newVal?.id) {
      loadData();
      nextTick(() => {
        updateTreeSelection();
      });
    }
  },
  { deep: true }
);

const columns: PlusColumn[] = [
  {
    label: "权限",
    width: 120,
    prop: "permission",
    hasLabel: false
  }
];

// 加载所有数据
async function loadData() {
  loading.value = true;
  try {
    // 同时加载权限树和角色已分配的权限
    await Promise.all([loadPermissionTree(), loadRolePermissions()]);
  } catch (error) {
    ElMessage.error("加载权限数据失败");
  } finally {
    loading.value = false;
  }
}

// 加载权限树
async function loadPermissionTree() {
  try {
    const res = await getPermissionTree();
    if (res.success && res.data) {
      // 确保数据是数组类型
      permissionTree.value = Array.isArray(res.data) ? res.data : [res.data];
    }
  } catch (error) {
    ElMessage.error("加载权限树失败");
  }
}

// 加载角色已分配的权限
async function loadRolePermissions() {
  if (!props.roleInfo?.id) return;

  try {
    const res = await getRolePermissionList(props.roleInfo.id);

    // 处理不同的数据结构情况
    let rolePermissions: PermissionVO[] = [];

    if (res.data && Array.isArray(res.data)) {
      rolePermissions = res.data;
    } else if (
      res.data &&
      typeof res.data === "object" &&
      "records" in res.data &&
      Array.isArray(res.data.records)
    ) {
      rolePermissions = res.data.records;
    }

    // 提取权限ID并确保是字符串类型
    selectedPermissionIds.value = rolePermissions
      .map(permission => String(permission.id))
      .filter(Boolean);

    // 保存原始权限ID，用于比对变更
    originalPermissionIds.value = [...selectedPermissionIds.value];

    // 设置树的选中状态
    nextTick(() => {
      updateTreeSelection();
    });
  } catch (error) {
    ElMessage.error("加载角色权限失败");
  }
}

// 更新树的选中状态
function updateTreeSelection() {
  if (!treeRef.value || !selectedPermissionIds.value.length) return;

  // 清空当前选中状态
  treeRef.value.setCheckedKeys([], false);

  // 设置新的选中状态
  treeRef.value.setCheckedKeys(selectedPermissionIds.value);

  // 更新选中状态
  selectedPermissionIds.value = (
    treeRef.value.getCheckedKeys(false) as any[]
  ).map(id => String(id));
}

// 处理树节点选中状态变化
function handleCheckChange() {
  if (!treeRef.value) return;

  // 更新选中的权限ID，确保是字符串类型
  selectedPermissionIds.value = (
    treeRef.value.getCheckedKeys(false) as any[]
  ).map(id => String(id));
}

// 提交权限分配
async function handleSubmit() {
  if (!props.roleInfo?.id) return;

  loading.value = true;
  try {
    // 检查是否有变更
    const hasChanges = !areArraysEqual(
      selectedPermissionIds.value,
      originalPermissionIds.value
    );

    if (!hasChanges) {
      ElMessage.info("权限分配未变更");
      handleClose();
      return;
    }

    // 调用API分配权限
    const params: RolePermissionAssignParams = {
      roleId: props.roleInfo.id,
      permissionIds: selectedPermissionIds.value.map(id => id)
    };

    const res = await updateRolePermission(params);

    if (res.success) {
      ElMessage.success("权限分配成功");
      emit("success");
      handleClose();
    } else {
      ElMessage.error(res.message || "权限分配失败");
    }
  } catch (error) {
    ElMessage.error("权限分配失败");
  } finally {
    loading.value = false;
  }
}

// 关闭抽屉
function handleClose() {
  // 重置状态
  selectedPermissionIds.value = [];
  originalPermissionIds.value = [];
  emit("close");
}

// 比较两个数组是否相等
function areArraysEqual(arr1: string[], arr2: string[]): boolean {
  if (arr1.length !== arr2.length) return false;
  return [...arr1].sort().join(",") === [...arr2].sort().join(",");
}

// 全选权限
function selectAllPermissions() {
  if (treeRef.value) {
    // 获取所有节点，确保是字符串类型
    const allNodes = getAllTreeNodeIds(permissionTree.value);
    // 全选
    treeRef.value.setCheckedKeys(allNodes);
    // 更新选中状态
    selectedPermissionIds.value = (
      treeRef.value.getCheckedKeys(false) as any[]
    ).map(id => String(id));
  }
}

// 清空选择
function clearSelection() {
  if (treeRef.value) {
    treeRef.value.setCheckedKeys([]);
    selectedPermissionIds.value = [];
  }
}

// 获取树的所有节点ID
function getAllTreeNodeIds(tree: any[]): string[] {
  const ids: string[] = [];

  const traverse = (nodes: any[]) => {
    if (!nodes?.length) return;

    for (const node of nodes) {
      if (node.id) {
        ids.push(String(node.id));
      }
      if (node.children?.length) {
        traverse(node.children);
      }
    }
  };

  traverse(tree);
  return ids;
}

// 初始化
onMounted(() => {
  if (visible.value && props.roleInfo?.id) {
    loadData();
    nextTick(() => {
      updateTreeSelection();
    });
  }
});
</script>

<template>
  <div>
    <PlusDrawerForm
      v-model:visible="visible"
      size="25%"
      :form="{ columns }"
      :title="`角色权限分配: ${props.roleInfo?.name || ''}`"
      :loading="loading"
      @close="handleClose"
      @confirm="handleSubmit"
    >
      <template #plus-field-permission>
        <div v-if="!permissionTree || permissionTree.length === 0">
          暂无可分配权限
        </div>
        <div v-else class="w-full p-0">
          <!-- 操作按钮 -->
          <div class="permission-actions">
            <div class="permission-buttons">
              <el-button
                type="primary"
                size="small"
                @click="selectAllPermissions"
                >全选</el-button
              >
              <el-button type="warning" size="small" @click="clearSelection"
                >清空</el-button
              >
            </div>
            <div class="permission-counter">
              已选择: {{ selectedCount }} 个权限
            </div>
          </div>

          <!-- 权限树 -->
          <div class="permission-tree">
            <el-tree
              ref="treeRef"
              :data="permissionTree"
              node-key="id"
              show-checkbox
              default-expand-all
              highlight-current
              :props="{
                children: 'children',
                label: 'name'
              }"
              @check="handleCheckChange"
            >
              <template #default="{ node, data }">
                <span class="custom-tree-node">
                  <span class="permission-name">{{ node.label }}</span>
                  <span v-if="data.code" class="permission-code">{{
                    data.code
                  }}</span>
                </span>
              </template>
            </el-tree>
          </div>
        </div>
      </template>
    </PlusDrawerForm>
  </div>
</template>

<style scoped>
.permission-actions {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 10px;
}

.permission-buttons {
  display: flex;
  gap: 8px;
}

.permission-counter {
  font-size: 14px;
  color: #606266;
}

.permission-tree {
  height: 100%;
  padding: 10px;
  overflow: auto;
  border: 1px solid #ebeef5;
  border-radius: 4px;
}

.custom-tree-node {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
}

.permission-name {
  font-weight: 500;
}

.permission-code {
  margin-left: 8px;
  font-size: 12px;
  color: #8c8c8c;
}
</style>
